﻿using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Quartz;
using Quartz.Impl;
using Quartz.Impl.Matchers;
using Quartz.Impl.Triggers;
using Quartz.Spi;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Publicuse.Interface;
using Publicuse.Entity;

namespace Publicuse.Util.QuartZ
{
    public static class QuartzTaskExtension
    {
        private static List<QuzrtTaskOptions> _taskList = new List<QuzrtTaskOptions>();

        private static bool isInit = false;

        private static IServiceProvider _services = null;

        private static ISchedulerFactory _schedulerFactory = null;

        private static IMySqlSugarService _mySqlSugar = null;

        private static IWebHostEnvironment _env = null;

        /// <summary>
        /// 初始化作业配置文件+数据库数据读取
        /// </summary>
        /// <param name="services"></param>
        /// <param name="schedulerFactory"></param>
        /// <param name="baseService"></param>
        /// <param name="env"></param>
        public static void InitQuartzTask(IServiceProvider services, ISchedulerFactory schedulerFactory, IMySqlSugarService mySqlSugar, IWebHostEnvironment env)
        {
            if (!isInit)
            {
                _services = services;
                _schedulerFactory = schedulerFactory;
                _mySqlSugar = mySqlSugar;
                _env = env;
            }
        }

        /// <summary>
        /// 获取所有的作业
        /// </summary>
        /// <param name="schedulerFactory"></param>
        /// <param name="mySqlDapper"></param>
        /// <param name="query"></param>
        /// <returns></returns>
        public static async Task<CommonResult> GetJobs(this ISchedulerFactory schedulerFactory, IMySqlSugarService mySqlDapper, QuzrtTaskOptions query)
        {
            return await Task.Factory.StartNew(() =>
            {
                CommonResult result = new CommonResult();
                string msg = string.Empty;
                long totalCount = 0;
                List<QuzrtTaskOptions> list = new List<QuzrtTaskOptions>();
                var tableName = TableAtributeUtil.GetTable<QuzrtTaskOptions>();
                string sql = query.GetQueryString<QuzrtTaskOptions>(null);
                CommonQuery commonQuery = new CommonQuery()
                {
                    tableName = tableName,
                    sqlWhere = sql,
                    sortFile = query.sortFile,
                    sortType = query.sortType,
                    pageIndex = query.pageIndex,
                    pageSize = query.pageSize,
                    files = "*"
                };
                mySqlDapper.GetList<QuzrtTaskOptions>(commonQuery, out msg, out list, out totalCount);
                result.count = totalCount;
                result.data = list;
                return result;
            });
        }

        /// <summary>
        /// 添加作业
        /// </summary>
        /// <param name="taskOptions"></param>
        /// <param name="schedulerFactory"></param>
        /// <param name="init">是否初始化,否=需要重新生成配置文件，是=不重新生成配置文件</param>
        /// <returns></returns>
        public static async Task<CommonResult> AddJob(this QuzrtTaskOptions taskOptions, IMySqlSugarService baseService, ISchedulerFactory schedulerFactory, bool init = false, IJobFactory jobFactory = null)
        {
            CommonResult result = new CommonResult();
            try
            {
                (bool, string) validExpression = taskOptions.Intervale.IsValidExpression();
                if (!validExpression.Item1)
                {
                    result.msg = $"时间执行间隔格式不正确：{validExpression.Item2}，请检查！";
                }
                if (!result.success)
                {
                    return result;
                }
                else
                {
                    result = taskOptions.Exists(init);
                    if (!init)
                    {
                        _taskList.Add(taskOptions);
                    }
                }
                IJobDetail job = JobBuilder.Create<HttpResultfulJob>()
                      .WithIdentity(taskOptions.TaskName, taskOptions.GroupName)
                     .Build();
                ITrigger trigger = TriggerBuilder.Create()
                   .WithIdentity(taskOptions.TaskName, taskOptions.GroupName)
                   .StartNow()
                   .WithDescription(taskOptions.Remark)
                   .WithCronSchedule(taskOptions.Intervale)
                   .Build();

                IScheduler scheduler = await schedulerFactory.GetScheduler();

                if (jobFactory == null)
                {
                    try
                    {
                        jobFactory = HttpContextExtendBase.Current.RequestServices.GetService<IJobFactory>();
                    }
                    catch (Exception ex)
                    {
                        result.msg = $"创建任务[{taskOptions.TaskName}]异常,{ex.Message}";
                        return result;
                    }
                }

                if (jobFactory != null)
                {
                    scheduler.JobFactory = jobFactory;
                }

                await scheduler.ScheduleJob(job, trigger);
                await scheduler.Start();
                if (!init)
                {
                    return result;
                }
            }
            catch (Exception ex)
            {
                result.msg = ex.Message;
            }
            return result;
        }

        /// <summary>
        /// 移除作业
        /// </summary>
        /// <param name="schedulerFactory"></param>
        /// <param name="taskOptions"></param>
        /// <param name="action"></param>
        /// <returns></returns>
        public static Task<CommonResult> Remove(this ISchedulerFactory schedulerFactory, IMySqlSugarService baseService, QuzrtTaskOptions taskOptions)
        {
            return schedulerFactory.TriggerAction(baseService, taskOptions.TaskName, taskOptions.GroupName, QuartzJobAction.Delete, taskOptions);
        }

        /// <summary>
        /// 更新作业
        /// </summary>
        /// <param name="schedulerFactory"></param>
        /// <param name="mySqlDapper"></param>
        /// <param name="taskOptions"></param>
        /// <returns></returns>
        public static Task<CommonResult> Update(this ISchedulerFactory schedulerFactory, IMySqlSugarService baseService, QuzrtTaskOptions taskOptions)
        {
            return schedulerFactory.TriggerAction(baseService, taskOptions.TaskName, taskOptions.GroupName, QuartzJobAction.Update, taskOptions);
        }

        /// <summary>
        /// 暂停作业
        /// </summary>
        /// <param name="schedulerFactory"></param>
        /// <param name="taskOptions"></param>
        /// <returns></returns>
        public static Task<CommonResult> Pause(this ISchedulerFactory schedulerFactory, IMySqlSugarService baseService, QuzrtTaskOptions taskOptions)
        {
            return schedulerFactory.TriggerAction(baseService, taskOptions.TaskName, taskOptions.GroupName, QuartzJobAction.Suspend, taskOptions);
        }

        /// <summary>
        /// 启动作业
        /// </summary>
        /// <param name="schedulerFactory"></param>
        /// <param name="taskOptions"></param>
        /// <returns></returns>
        public static Task<CommonResult> Start(this ISchedulerFactory schedulerFactory, IMySqlSugarService baseService, QuzrtTaskOptions taskOptions)
        {
            return schedulerFactory.TriggerAction(baseService, taskOptions.TaskName, taskOptions.GroupName, QuartzJobAction.Start, taskOptions);
        }

        /// <summary>
        /// 启动所有作业
        /// </summary>
        /// <param name="schedulerFactory"></param>
        /// <returns></returns>
        public static Task<CommonResult> StartAll(this ISchedulerFactory schedulerFactory)
        {
            return schedulerFactory.StartAllAction(QuartzJobAction.StartAll);
        }

        /// <summary>
        /// 重新加载配置启动后台任务
        /// </summary>
        /// <param name="schedulerFactory"></param>
        /// <returns></returns>
        public static Task<CommonResult> Init(this ISchedulerFactory schedulerFactory)
        {
            return schedulerFactory.InitTask();
        }

        /// <summary>
        /// 立即执行一次作业
        /// </summary>
        /// <param name="schedulerFactory"></param>
        /// <param name="taskOptions"></param>
        /// <returns></returns>
        public static Task<CommonResult> Run(this ISchedulerFactory schedulerFactory, IMySqlSugarService baseService, QuzrtTaskOptions taskOptions)
        {
            return schedulerFactory.TriggerAction(baseService, taskOptions.TaskName, taskOptions.GroupName, QuartzJobAction.Run, taskOptions);
        }

        /// <summary>
        /// 停止作业
        /// </summary>
        /// <param name="schedulerFactory"></param>
        /// <param name="taskOptions"></param>
        /// <returns></returns>
        public static Task<CommonResult> Stop(this ISchedulerFactory schedulerFactory, IMySqlSugarService baseService, QuzrtTaskOptions taskOptions)
        {
            return schedulerFactory.TriggerAction(baseService, taskOptions.TaskName, taskOptions.GroupName, QuartzJobAction.Stop, taskOptions);
        }

        /// <summary>
        /// 停止所有作业
        /// </summary>
        /// <param name="schedulerFactory"></param>
        /// <param name="taskOptions"></param>
        /// <returns></returns>
        public static Task<CommonResult> StopAll(this ISchedulerFactory schedulerFactory, IMySqlSugarService baseService)
        {
            return schedulerFactory.StopAllAction(QuartzJobAction.StopAll, baseService);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="schedulerFactory"></param>
        /// <param name="action"></param>
        /// <returns></returns>
        public static async Task<CommonResult> StartAllAction(this ISchedulerFactory schedulerFactory, QuartzJobAction action)
        {
            CommonResult result = new CommonResult();
            try
            {
                IScheduler scheduler = await schedulerFactory.GetScheduler();
                await scheduler.Start();
            }
            catch (Exception ex)
            {
                result.msg = ex.Message;
            }
            return result;
        }

        /// <summary>
        /// 重新加载配置启动后台任务
        /// </summary>
        /// <param name="schedulerFactory"></param>
        /// <returns></returns>
        public static async Task<CommonResult> InitTask(this ISchedulerFactory schedulerFactory)
        {
            CommonResult result = new CommonResult();
            try
            {
                IScheduler scheduler = await schedulerFactory.GetScheduler();
                if (scheduler.IsStarted)
                {
                    await scheduler.Shutdown();
                }
                _taskList.Clear();
                InitQuartzTask(_services, _schedulerFactory, _mySqlSugar, _env);
            }
            catch (Exception ex)
            {
                result.msg = ex.Message;
            }
            return result;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="schedulerFactory"></param>
        /// <param name="action"></param>
        /// <returns></returns>
        public static async Task<CommonResult> StopAllAction(this ISchedulerFactory schedulerFactory, QuartzJobAction action, IMySqlSugarService baseService)
        {
            CommonResult result = new CommonResult();
            try
            {
                IScheduler scheduler = await schedulerFactory.GetScheduler();
                if (scheduler.IsStarted)
                {
                    await scheduler.Standby();
                }
            }
            catch (Exception ex)
            {
                result.msg = ex.Message;
            }
            return result;
        }

        /// <summary>
        /// Delete、Update、Suspend、Start、Run
        /// </summary>
        /// <param name="schedulerFactory"></param>
        /// <param name="taskName"></param>
        /// <param name="groupName"></param>
        /// <param name="action"></param>
        /// <param name="taskOptions"></param>
        /// <returns></returns>
        public static async Task<CommonResult> TriggerAction(this ISchedulerFactory schedulerFactory, IMySqlSugarService baseService, string taskName, string groupName, QuartzJobAction action, QuzrtTaskOptions taskOptions = null)
        {
            CommonResult result = new CommonResult();
            string msg = string.Empty;
            string sql = string.Empty;
            try
            {
                var table = TableAtributeUtil.GetTable<QuzrtTaskOptions>();
                IScheduler scheduler = await schedulerFactory.GetScheduler();
                if (_taskList.Count == 0)
                {
                    if (action == QuartzJobAction.Add || action == QuartzJobAction.Run || action == QuartzJobAction.Start)
                    {
                        taskOptions.AddJob(baseService, schedulerFactory, false, jobFactory: _services.GetService<IJobFactory>()).GetAwaiter().GetResult();
                    }
                    if (action == QuartzJobAction.Delete)
                    {
                        return result;
                    }
                    if (action == QuartzJobAction.Suspend)
                    {
                        result.msg = "该后台作业【" + groupName + "-" + taskName + "】还没有启动运行！";
                        return result;
                    }
                    if (action == QuartzJobAction.Stop)
                    {
                        result.msg = "该后台作业【" + groupName + "-" + taskName + "】还没有启动运行！";
                        return result;
                    }
                }
                else
                {
                    TriggerKey triggerKey = new TriggerKey(taskOptions.TaskName, taskOptions.GroupName);
                    var state = scheduler.GetTriggerState(triggerKey).GetAwaiter().GetResult();
                    if (action == QuartzJobAction.Start)
                    {
                        if (state == TriggerState.Normal)
                        {
                            result.msg = "已经开启运行中，无需再开启！";
                            return result;
                        }
                        if (state == TriggerState.None)
                        {
                            taskOptions.AddJob(baseService, schedulerFactory, true, jobFactory: _services.GetService<IJobFactory>()).GetAwaiter().GetResult();
                            return result;
                        }
                    }
                    if (action == QuartzJobAction.Run)
                    {
                        if (state == TriggerState.None || state==TriggerState.Normal)
                        {
                            result=taskOptions.AddJob(baseService, schedulerFactory, true, jobFactory: _services.GetService<IJobFactory>()).GetAwaiter().GetResult();
                            return result;
                        }
                    }
                    if (action == QuartzJobAction.Suspend || action == QuartzJobAction.Delete || action == QuartzJobAction.Stop)
                    {
                        if (state == TriggerState.None)
                        {
                            result.msg = "该后台作业【" + groupName + "-" + taskName + "】还没有启动运行！";
                            return result;
                        }
                    }
                }
                List<JobKey> jobKeys = scheduler.GetJobKeys(GroupMatcher<JobKey>.GroupEquals(taskOptions.GroupName)).Result.ToList();
                if (jobKeys == null || jobKeys.Count() == 0)
                {
                    result.msg = $"未找到工作【{taskOptions.GroupName}-{taskOptions.TaskName}】作业";
                    return result;
                }
                JobKey jobKey = jobKeys.Where(s => scheduler.GetTriggersOfJob(s).Result.Any(x => (x as CronTriggerImpl).Name == taskName)).FirstOrDefault();
                if (jobKey == null)
                {
                    result.msg = $"未找到触发器【{taskOptions.GroupName}-{taskOptions.TaskName}】作业";
                    return result;
                }
                var triggers = await scheduler.GetTriggersOfJob(jobKey);
                ITrigger trigger = triggers?.Where(x => (x as CronTriggerImpl).Name == taskOptions.TaskName).FirstOrDefault();

                if (trigger == null)
                {
                    result.msg = $"未找到触发器【{taskOptions.GroupName}-{taskOptions.TaskName}】作业";
                    return result;
                }
                switch (action)
                {
                    case QuartzJobAction.StartAll:
                        await scheduler.Start();
                        break;
                    case QuartzJobAction.StopAll:
                        await scheduler.Shutdown();
                        break;
                    case QuartzJobAction.Delete:
                    case QuartzJobAction.Update:
                        await scheduler.PauseTrigger(trigger.Key);
                        await scheduler.UnscheduleJob(trigger.Key);
                        await scheduler.DeleteJob(trigger.JobKey);
                        break;
                    case QuartzJobAction.Suspend:
                    case QuartzJobAction.Stop:
                    case QuartzJobAction.Start:
                        if (action == QuartzJobAction.Suspend)
                        {
                            await scheduler.PauseTrigger(trigger.Key);
                        }
                        else if (action == QuartzJobAction.Start)
                        {
                            if (!scheduler.IsStarted)
                            {
                                await scheduler.Start();
                            }
                            await scheduler.ResumeTrigger(trigger.Key);
                        }
                        else
                        {
                            await scheduler.UnscheduleJob(trigger.Key);
                        }
                        break;
                    case QuartzJobAction.Run:
                        if (!scheduler.IsStarted)
                        {
                            await scheduler.Start();
                        }
                        await scheduler.TriggerJob(jobKey);
                        break;
                }
            }
            catch (Exception ex)
            {
                result.msg = ex.Message;
            }
            finally
            {
            }
            return result;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="context"></param>通过作业上下文获取作业对应的配置参数
        /// <returns></returns>
        public static QuzrtTaskOptions GetTaskOptions(this IJobExecutionContext context)
        {
            AbstractTrigger trigger = (context as JobExecutionContextImpl).Trigger as AbstractTrigger;
            var table = TableAtributeUtil.GetTable<QuzrtTaskOptions>();
            var sql = $"select * from {table} where TaskName='{trigger.JobName}' and GroupName='{trigger.JobGroup}';";
            QuzrtTaskOptions taskOptions = new QuzrtTaskOptions();
            var data = _mySqlSugar.Query<QuzrtTaskOptions>(sql, out var msg);
            if(string.IsNullOrEmpty(msg) && data.Count > 0)
            {
                taskOptions = data.FirstOrDefault();
                if (taskOptions == null)
                {
                    taskOptions = _taskList.Where(x => x.TaskName == trigger.Name && x.GroupName == trigger.Group).FirstOrDefault();
                }
            }
      
            return taskOptions;
        }

        /// <summary>
        /// 作业是否存在
        /// </summary>
        /// <param name="taskOptions"></param>
        /// <param name="init">初始化的不需要判断</param>
        /// <returns></returns>
        public static CommonResult Exists(this QuzrtTaskOptions taskOptions, bool init)
        {
            CommonResult result = new CommonResult();
            if (!init && _taskList.Any(x => x.TaskName == taskOptions.TaskName && x.GroupName == taskOptions.GroupName
            && x.ApiUrl == taskOptions.ApiUrl && x.RequestType == taskOptions.RequestType))
            {
                result.msg = $"作业:{taskOptions.TaskName},分组：{taskOptions.GroupName}已经存在";
            }
            return result;
        }

        public static (bool, string) IsValidExpression(this string cronExpression)
        {
            try
            {
                CronTriggerImpl trigger = new CronTriggerImpl();
                trigger.CronExpressionString = cronExpression;
                DateTimeOffset? date = trigger.ComputeFirstFireTimeUtc(null);
                return (date != null, date == null ? $"请确认表达式{cronExpression}是否正确!" : "");
            }
            catch (Exception e)
            {
                return (false, $"请确认表达式{cronExpression}是否正确!{e.Message}");
            }
        }
    }
}
